﻿using HelixToolkit.Wpf;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace PlyViewer
{
    public partial class MainWindow : Window
    {
        #region 字段和变量声明
        // 点云可视化相关
        private ModelVisual3D currentPointCloud;
        private PlyPointCloud loadedPointCloud;
        private HighPerformancePointCloudRenderer pointCloudRenderer;

        // 性能和状态监控
        private DispatcherTimer performanceTimer;
        private Stopwatch loadStopwatch;
        private int frameCount = 0;
        private DateTime lastFpsUpdate = DateTime.Now;

        // 设置持久化
        private IsolatedStorageFile isolatedStorage;

        // 渲染设置
        private bool useHeightColoring = false;
        #endregion

        #region 构造函数和初始化
        /// <summary>
        /// 主窗口构造函数
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
            InitializeViewport();
            InitializePerformanceMonitoring();
            LoadSettings();
        }

        /// <summary>
        /// 初始化3D视口设置
        /// 注意：设置相机参数、背景颜色和交互模式
        /// </summary>
        private void InitializeViewport()
        {
            // 优化视口设置
            Viewport3D.ShowFrameRate = true;
            Viewport3D.RotateAroundMouseDownPoint = true;
            Viewport3D.ZoomAroundMouseDownPoint = true;
            Viewport3D.CameraRotationMode = CameraRotationMode.Turntable;

            // 设置黑色背景
            Viewport3D.Background = new SolidColorBrush(Color.FromRgb(10, 21, 32));

            // 添加默认光源
            Viewport3D.Children.Add(new DefaultLights());

            // 设置优化的相机
            // 参数说明：
            // Position: 相机初始位置
            // LookDirection: 相机观察方向  
            // UpDirection: 相机上方向
            // FieldOfView: 视野角度
            var camera = new PerspectiveCamera
            {
                Position = new Point3D(2, 2, 2),
                LookDirection = new Vector3D(-2, -2, -2),
                UpDirection = new Vector3D(0, 0, 1),
                FieldOfView = 60,
                NearPlaneDistance = 0.1,
                FarPlaneDistance = 1000
            };
            Viewport3D.Camera = camera;
        }

        /// <summary>
        /// 初始化性能监控系统
        /// 包括帧率监控和内存使用监控
        /// </summary>
        private void InitializePerformanceMonitoring()
        {
            // 性能监控定时器
            performanceTimer = new DispatcherTimer();
            performanceTimer.Interval = TimeSpan.FromSeconds(1);
            performanceTimer.Tick += (s, e) => UpdatePerformanceInfo();
            performanceTimer.Start();

            // 帧率监控
            CompositionTarget.Rendering += (s, e) =>
            {
                frameCount++;
                var now = DateTime.Now;
                if ((now - lastFpsUpdate).TotalSeconds >= 1)
                {
                    UpdatePerformanceInfo();
                    lastFpsUpdate = now;
                    frameCount = 0;
                }
            };
        }
        #endregion

        #region 设置持久化管理
        /// <summary>
        /// 加载用户设置（文件夹路径和产品序列号）
        /// 使用IsolatedStorage进行数据持久化
        /// </summary>
        private void LoadSettings()
        {
            try
            {
                isolatedStorage = IsolatedStorageFile.GetUserStoreForAssembly();

                // 加载文件夹路径
                if (isolatedStorage.FileExists("FolderPath.txt"))
                {
                    using (var stream = new IsolatedStorageFileStream("FolderPath.txt", FileMode.Open, isolatedStorage))
                    using (var reader = new StreamReader(stream))
                    {
                        FolderPathTextBox.Text = reader.ReadToEnd();
                    }
                }

                // 加载产品序列号
                if (isolatedStorage.FileExists("ProductId.txt"))
                {
                    using (var stream = new IsolatedStorageFileStream("ProductId.txt", FileMode.Open, isolatedStorage))
                    using (var reader = new StreamReader(stream))
                    {
                        ProductIdTextBox.Text = reader.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"加载设置时出错: {ex.Message}");
            }
        }

        /// <summary>
        /// 保存用户设置到隔离存储
        /// </summary>
        private void SaveSettings()
        {
            try
            {
                // 保存文件夹路径
                using (var stream = new IsolatedStorageFileStream("FolderPath.txt", FileMode.Create, isolatedStorage))
                using (var writer = new StreamWriter(stream))
                {
                    writer.Write(FolderPathTextBox.Text);
                }

                // 保存产品序列号
                using (var stream = new IsolatedStorageFileStream("ProductId.txt", FileMode.Create, isolatedStorage))
                using (var writer = new StreamWriter(stream))
                {
                    writer.Write(ProductIdTextBox.Text);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"保存设置时出错: {ex.Message}");
            }
        }
        #endregion

        #region 性能监控和状态更新
        /// <summary>
        /// 更新性能信息显示
        /// 显示内存使用和实时帧率
        /// </summary>
        private void UpdatePerformanceInfo()
        {
            if (loadedPointCloud != null)
            {
                var memory = GC.GetTotalMemory(false) / 1024 / 1024;
                PerformanceText.Text = $"内存: {memory}MB | 帧率: {frameCount}FPS";
            }
        }
        #endregion

        #region 文件操作和点云加载
        /// <summary>
        /// 打开文件按钮点击事件
        /// 弹出文件选择对话框选择PLY文件
        /// </summary>
        private void OpenFile_Click(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new OpenFileDialog
            {
                Filter = "PLY文件 (*.ply)|*.ply|所有文件 (*.*)|*.*",
                Title = "选择PLY点云文件"
            };

            if (openFileDialog.ShowDialog() == true)
            {
                LoadPlyFile(openFileDialog.FileName);
            }
        }

        /// <summary>
        /// 加载PLY文件的主要方法
        /// 参数说明：
        /// filePath - PLY文件的完整路径
        /// 注意：会自动尝试二进制格式，失败后回退到ASCII格式
        /// </summary>
        private void LoadPlyFile(string filePath)
        {
            try
            {
                // 检查文件是否存在
                if (!File.Exists(filePath))
                {
                    MessageBox.Show($"文件不存在: {filePath}", "错误",
                        MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                // 检查文件扩展名
                if (!IsPlyFile(filePath))
                {
                    MessageBox.Show("请选择有效的PLY文件", "文件格式错误",
                        MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }

                loadStopwatch = Stopwatch.StartNew();
                StatusText.Text = "正在加载文件...";

                PlyPointCloud pointCloud;

                // 首先尝试二进制读取器
                try
                {
                    Debug.WriteLine("尝试二进制读取器...");
                    pointCloud = BinaryPlyReader.ReadBinaryPlyFile(filePath);
                }
                catch (Exception binaryEx)
                {
                    // 如果二进制读取失败，回退到ASCII读取器
                    Debug.WriteLine($"二进制读取失败，尝试ASCII: {binaryEx.Message}");
                    pointCloud = PlyReader.ReadPlyFile(filePath);
                }

                loadedPointCloud = pointCloud;

                // 输出加载信息
                loadStopwatch.Stop();
                Debug.WriteLine($"点云加载完成: {pointCloud.Points.Count} 个点, 耗时: {loadStopwatch.ElapsedMilliseconds}ms");

                // 清除现有点云
                Viewport3D.Children.Clear();
                Viewport3D.Children.Add(new DefaultLights());

                // 获取细节级别设置
                double detailLevel = GetDetailLevel();

                // 使用高性能渲染器
                pointCloudRenderer = new HighPerformancePointCloudRenderer();
                currentPointCloud = pointCloudRenderer.CreateOptimizedVisual(
                    loadedPointCloud,
                    PointSizeSlider.Value,
                    detailLevel,
                    useHeightColoring); // 传递高度着色标志

                Viewport3D.Children.Add(currentPointCloud);

                // 更新状态
                StatusText.Text = $"已加载: {loadedPointCloud.FileName} (优化)";
                PointCountText.Text = $"显示点数: {pointCloudRenderer.DisplayedPointCount:N0} / 总数: {loadedPointCloud.Points.Count:N0}";

                // 自动调整视图
                Viewport3D.Camera.Reset();
                Viewport3D.ZoomExtents();

            }
            catch (Exception ex)
            {
                string errorMessage = $"加载文件时出错:\n{ex.Message}";
                if (ex.InnerException != null)
                {
                    errorMessage += $"\n内部错误: {ex.InnerException.Message}";
                }

                MessageBox.Show(errorMessage, "错误",
                    MessageBoxButton.OK, MessageBoxImage.Error);
                StatusText.Text = "加载失败";
                Debug.WriteLine($"错误详情: {ex}");
            }
        }

        /// <summary>
        /// 检查文件是否为PLY格式
        /// 参数说明：
        /// filePath - 要检查的文件路径
        /// 返回值：true表示是PLY文件，false表示不是
        /// </summary>
        private bool IsPlyFile(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
                return false;

            string extension = Path.GetExtension(filePath).ToLower();
            return extension == ".ply";
        }
        #endregion

        #region 点云渲染设置控制
        /// <summary>
        /// 获取当前选择的细节级别
        /// 返回值：0.05-1.0之间的细节级别值
        /// </summary>
        private double GetDetailLevel()
        {
            var selectedItem = DetailLevelComboBox.SelectedItem as ComboBoxItem;
            if (selectedItem?.Tag != null && double.TryParse(selectedItem.Tag.ToString(), out double level))
            {
                return level;
            }
            return 0.5; // 默认中等细节
        }

        /// <summary>
        /// 点大小滑块值改变事件
        /// 参数说明：
        /// e.NewValue - 新的点大小值（1-10）
        /// </summary>
        private void PointSizeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (loadedPointCloud != null && pointCloudRenderer != null)
            {
                // 更新点大小而不重新创建整个点云
                pointCloudRenderer.UpdatePointSize(e.NewValue);
            }
        }

        /// <summary>
        /// 细节级别选择改变事件
        /// 重新创建点云以应用新的细节级别
        /// </summary>
        private void DetailLevel_Changed(object sender, SelectionChangedEventArgs e)
        {
            if (loadedPointCloud != null && pointCloudRenderer != null)
            {
                double detailLevel = GetDetailLevel();

                // 重新创建点云以应用新的细节级别
                Viewport3D.Children.Remove(currentPointCloud);
                currentPointCloud = pointCloudRenderer.CreateOptimizedVisual(
                    loadedPointCloud,
                    PointSizeSlider.Value,
                    detailLevel,
                    useHeightColoring);

                Viewport3D.Children.Add(currentPointCloud);

                PointCountText.Text = $"显示点数: {pointCloudRenderer.DisplayedPointCount:N0} / 总数: {loadedPointCloud.Points.Count:N0}";
            }
        }

        /// <summary>
        /// 点云着色复选框改变事件
        /// 切换按高度着色和白色显示模式
        /// </summary>
        private void ColorByHeightCheckBox_Changed(object sender, RoutedEventArgs e)
        {
            useHeightColoring = ColorByHeightCheckBox.IsChecked ?? false;

            if (loadedPointCloud != null && pointCloudRenderer != null)
            {
                // 重新创建点云以应用新的着色方式
                Viewport3D.Children.Remove(currentPointCloud);

                double detailLevel = GetDetailLevel();
                currentPointCloud = pointCloudRenderer.CreateOptimizedVisual(
                    loadedPointCloud,
                    PointSizeSlider.Value,
                    detailLevel,
                    useHeightColoring);

                Viewport3D.Children.Add(currentPointCloud);
            }
        }
        #endregion

        #region 视图控制
        /// <summary>
        /// 重置视图按钮点击事件
        /// 将相机重置到初始位置并缩放到合适大小
        /// </summary>
        private void ResetView_Click(object sender, RoutedEventArgs e)
        {
            Viewport3D.Camera.Reset();
            Viewport3D.ZoomExtents();
        }
        #endregion

        #region 点云生成功能
        /// <summary>
        /// 生成点云按钮点击事件
        /// 根据输入的图像文件夹和产品序列号生成点云
        /// 注意：此方法为异步执行，避免界面卡顿
        /// </summary>
        private async void GeneratePointCloudButton_Click(object sender, RoutedEventArgs e)
        {
            string folderPath = FolderPathTextBox.Text.Trim();
            string productId = ProductIdTextBox.Text.Trim();

            if (string.IsNullOrEmpty(folderPath))
            {
                MessageBox.Show("请输入图像文件夹地址", "错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (string.IsNullOrEmpty(productId))
            {
                MessageBox.Show("请输入产品序列号", "错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            try
            {
                // 保存设置
                SaveSettings();

                // 禁用按钮防止重复点击
                GeneratePointCloudButton.IsEnabled = false;
                GenerationStatusText.Text = "正在处理...";
                GenerationStatusText.Foreground = new SolidColorBrush(Color.FromRgb(255, 215, 0)); // 金色

                // 在后台执行生成操作
                await Task.Run(() => GeneratePointCloud(folderPath, productId));

                // 加载生成的点云文件
                string generatedPlyPath = Path.Combine(Directory.GetCurrentDirectory(), "points.ply");
                if (File.Exists(generatedPlyPath))
                {
                    LoadPlyFile(generatedPlyPath);
                    GenerationStatusText.Text = "点云生成成功!";
                    GenerationStatusText.Foreground = new SolidColorBrush(Color.FromRgb(0, 255, 136)); // 绿色
                }
                else
                {
                    GenerationStatusText.Text = "点云文件未找到";
                    GenerationStatusText.Foreground = new SolidColorBrush(Color.FromRgb(255, 87, 87)); // 红色
                }
            }
            catch (Exception ex)
            {
                GenerationStatusText.Text = $"生成失败: {ex.Message}";
                GenerationStatusText.Foreground = new SolidColorBrush(Color.FromRgb(255, 87, 87)); // 红色
                Debug.WriteLine($"点云生成错误: {ex}");
            }
            finally
            {
                GeneratePointCloudButton.IsEnabled = true;
            }
        }

        /// <summary>
        /// 生成点云的核心逻辑
        /// 参数说明：
        /// folderPath - 图像文件夹路径
        /// productId - 产品序列号
        /// 注意：会调用外部contour.exe程序进行点云生成
        /// </summary>
        private void GeneratePointCloud(string folderPath, string productId)
        {
            // 构建图像文件路径
            string image1Path = Path.Combine(folderPath, $"{productId}_0.png");
            string image2Path = Path.Combine(folderPath, $"{productId}_1.png");

            // 检查图像文件是否存在
            if (!File.Exists(image1Path) || !File.Exists(image2Path))
            {
                throw new FileNotFoundException($"找不到图像文件: {image1Path} 或 {image2Path}");
            }

            // 获取当前工作目录
            string currentDirectory = Directory.GetCurrentDirectory();
            string localImage1Path = Path.Combine(currentDirectory, "1.png");
            string localImage2Path = Path.Combine(currentDirectory, "2.png");

            try
            {
                // 复制图像文件到本地
                File.Copy(image1Path, localImage1Path, true);
                File.Copy(image2Path, localImage2Path, true);

                // 延时1秒
                System.Threading.Thread.Sleep(1000);

                // 调用contour.exe程序
                string contourExePath = Path.Combine(currentDirectory, "contour.exe");

                if (!File.Exists(contourExePath))
                {
                    throw new FileNotFoundException($"找不到contour.exe程序: {contourExePath}");
                }

                ProcessStartInfo startInfo = new ProcessStartInfo
                {
                    FileName = contourExePath,
                    WorkingDirectory = currentDirectory,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true
                };

                using (Process process = new Process())
                {
                    process.StartInfo = startInfo;
                    process.Start();

                    // 读取输出信息
                    string output = process.StandardOutput.ReadToEnd();
                    string error = process.StandardError.ReadToEnd();

                    process.WaitForExit();

                    if (process.ExitCode != 0)
                    {
                        throw new Exception($"contour.exe执行失败 (退出代码: {process.ExitCode})\n错误信息: {error}");
                    }

                    Debug.WriteLine($"contour.exe输出: {output}");
                }
            }
            finally
            {
                // 清理临时图像文件
                try
                {
                    if (File.Exists(localImage1Path))
                        File.Delete(localImage1Path);
                    if (File.Exists(localImage2Path))
                        File.Delete(localImage2Path);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"清理临时文件时出错: {ex.Message}");
                }
            }
        }
        #endregion

        #region 拖放功能
        /// <summary>
        /// 窗口拖拽进入事件
        /// 检查拖拽的文件是否为PLY格式并显示视觉反馈
        /// </summary>
        private void Window_DragEnter(object sender, DragEventArgs e)
        {
            // 检查拖放的数据中是否包含文件
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                // 获取文件路径
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

                // 检查是否是PLY文件
                if (files.Length > 0 && IsPlyFile(files[0]))
                {
                    // 显示拖放效果
                    e.Effects = DragDropEffects.Copy;

                    // 可选：更改窗口外观以提示用户
                    ChangeDragDropAppearance(true);
                }
                else
                {
                    e.Effects = DragDropEffects.None;
                }
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }

            e.Handled = true;
        }

        /// <summary>
        /// 窗口拖放事件
        /// 处理文件释放并加载PLY文件
        /// </summary>
        private void Window_Drop(object sender, DragEventArgs e)
        {
            // 恢复窗口外观
            ChangeDragDropAppearance(false);

            // 检查拖放的数据中是否包含文件
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                // 获取文件路径
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

                if (files.Length > 0 && IsPlyFile(files[0]))
                {
                    // 加载PLY文件
                    LoadPlyFile(files[0]);
                }
                else
                {
                    MessageBox.Show("请拖放有效的PLY文件", "文件格式错误",
                        MessageBoxButton.OK, MessageBoxImage.Warning);
                }
            }

            e.Handled = true;
        }

        /// <summary>
        /// 改变拖放时的窗口外观
        /// 参数说明：
        /// isDragging - 是否正在拖拽文件
        /// </summary>
        private void ChangeDragDropAppearance(bool isDragging)
        {
            if (isDragging)
            {
                // 拖拽进入时的视觉效果
                this.BorderBrush = new SolidColorBrush(Color.FromRgb(0, 212, 255)); // 霓虹蓝色
                this.BorderThickness = new Thickness(2);

                // 可选：添加提示信息
                StatusText.Text = "释放以加载PLY文件";
                StatusText.Foreground = new SolidColorBrush(Color.FromRgb(0, 212, 255));
            }
            else
            {
                // 恢复原始外观
                this.BorderBrush = Brushes.Transparent;
                this.BorderThickness = new Thickness(0);

                // 恢复状态文本
                if (loadedPointCloud != null)
                {
                    StatusText.Text = $"已加载: {loadedPointCloud.FileName} (优化)";
                    StatusText.Foreground = Brushes.White;
                }
                else
                {
                    StatusText.Text = "就绪";
                    StatusText.Foreground = Brushes.White;
                }
            }
        }
        #endregion

        #region 自定义标题栏功能
        /// <summary>
        /// 标题栏鼠标按下事件
        /// 支持拖拽移动窗口和双击最大化
        /// </summary>
        private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Left)
            {
                if (e.ClickCount == 2)
                {
                    // 双击标题栏切换最大化状态
                    ToggleMaximize();
                }
                else
                {
                    // 拖拽窗口
                    this.DragMove();
                }
            }
        }

        /// <summary>
        /// 最小化按钮点击事件
        /// </summary>
        private void MinimizeButton_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = WindowState.Minimized;
        }

        /// <summary>
        /// 最大化按钮点击事件
        /// </summary>
        private void MaximizeButton_Click(object sender, RoutedEventArgs e)
        {
            ToggleMaximize();
        }

        /// <summary>
        /// 关闭按钮点击事件
        /// </summary>
        private void CloseButton_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// 切换窗口最大化状态
        /// 注意：最大化时添加边距避免内容被任务栏遮挡
        /// </summary>
        private void ToggleMaximize()
        {
            if (this.WindowState == WindowState.Maximized)
            {
                this.WindowState = WindowState.Normal;
                // 移除最大化后的边距
                this.BorderThickness = new Thickness(0);
            }
            else
            {
                this.WindowState = WindowState.Maximized;
                // 添加边距以避免内容被任务栏遮挡
                this.BorderThickness = new Thickness(8);
            }
        }

        /// <summary>
        /// 窗口状态改变事件
        /// 更新最大化按钮的显示文本
        /// </summary>
        protected override void OnStateChanged(EventArgs e)
        {
            base.OnStateChanged(e);

            // 更新最大化按钮文本
            if (this.WindowState == WindowState.Maximized)
            {
                MaximizeButton.Content = "❐"; // 还原图标
                // 添加边距以避免内容被任务栏遮挡
                this.BorderThickness = new Thickness(8);
            }
            else
            {
                MaximizeButton.Content = "□"; // 最大化图标
                // 移除边距
                this.BorderThickness = new Thickness(0);
            }
        }
        #endregion

        #region 窗口生命周期事件
        /// <summary>
        /// 窗口关闭事件
        /// 保存用户设置并停止性能监控
        /// </summary>
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // 保存设置
            SaveSettings();
            performanceTimer?.Stop();
        }

        /// <summary>
        /// 窗口关闭后事件
        /// 确保性能监控定时器被正确停止
        /// </summary>
        protected override void OnClosed(EventArgs e)
        {
            performanceTimer?.Stop();
            base.OnClosed(e);
        }
        #endregion
    }
}